package com.spring;

import java.beans.Introspector;
import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ApplicationContext {
    private Class configClass;
    private Map<String,BeanDefinition> beanDefinitionMap = new HashMap<>();
    private Map<String,Object> singletonObject = new HashMap<>();
    private List<BeanPostProcessor> beanPostProcessors = new ArrayList<>();

    public ApplicationContext(Class main) {
        this.configClass = main;
        //TODO 创建容器
        //扫描包
        scan(main);
        // 创建bean
        beanDefinitionMap.forEach((k,v)->{
            if(v.scope.equals("singleton")){
                Object bean = createBean(k, v);
                singletonObject.put(k,bean);
            }
        });

    }
    private Object createBean(String beanName,BeanDefinition beanDefinition){
        Class clazz = beanDefinition.getType();
        Object instance = null;
        try {
            // 推断构造
            instance = clazz.getConstructor().newInstance();
            // 属性注入的部分
            for (Field field : clazz.getDeclaredFields()) {
                if(field.isAnnotationPresent(Autowired.class)){
                    Autowired annotation = field.getAnnotation(Autowired.class);
                    String fieldName;
                    if(annotation.value().equals("")){
                       fieldName = field.getName();
                    }else {
                        fieldName = annotation.value();
                    }
                    Object bean = getBean(fieldName);
                    field.setAccessible(true);
                    field.set(instance,bean);
                }
            }
            //初始化前
            for (int i = 0; i < beanPostProcessors.size(); i++) {
                instance = beanPostProcessors.get(i).postProcessBeforeInitialization(instance,beanName);
            }
            // 初始化
            if(instance instanceof InitializingBean){
                ((InitializingBean)instance).afterPropertiesSet();
            }
            //初始化后
            for (int i = 0; i < beanPostProcessors.size(); i++) {
                instance = beanPostProcessors.get(i).postProcessAfterInitialization(instance,beanName);
            }

        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        return instance;
    }

    private void scan(Class main) {
        // 扫描包
        ComponentScan componentScan = (ComponentScan) main.getAnnotation(ComponentScan.class);
        String path = componentScan.value().replace(".","/");
        ClassLoader classLoader = main.getClassLoader();
        URL resource = classLoader.getResource(path);
        File file = new File(resource.getFile());

        if(file.isDirectory()){
            File[] files = file.listFiles();
            for (int i = 0; i < files.length; i++) {
                String absolutePath = files[i].getAbsolutePath();
                absolutePath = absolutePath.substring(absolutePath.indexOf("com"),absolutePath.indexOf(".class")).replaceAll("/", ".");
                try {
                    Class<?> clazz = classLoader.loadClass(absolutePath);
                    if(clazz.isAnnotationPresent(Component.class)){
                        if(BeanPostProcessor.class.isAssignableFrom(clazz)){
                            beanPostProcessors.add((BeanPostProcessor) clazz.getConstructor().newInstance());
                        }else {
                            BeanDefinition beanDefinition = new BeanDefinition();
                            beanDefinition.setType(clazz);
                            //说明是个bean
                            // 判断是单列还是多列
                            if(clazz.isAnnotationPresent(Scope.class)){
                                beanDefinition.setScope(clazz.getAnnotation(Scope.class).value());
                            }else {
                                beanDefinition.setScope("singleton");
                            }
                            String beanName = clazz.getAnnotation(Component.class).value();
                            if(beanName.equals("")){
                                beanName = Introspector.decapitalize(clazz.getSimpleName());
                            }
                            beanDefinitionMap.put(beanName,beanDefinition);
                        }

                    }
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                } catch (InstantiationException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (NoSuchMethodException e) {
                    e.printStackTrace();
                }

            }
        }
    }

    public Object getBean(String beanName){
        if(null == beanDefinitionMap.get(beanName)){
              throw new NullPointerException();
        }
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        // 创建bean
        if(beanDefinition.scope.equals("singleton")){
            Object bean = singletonObject.get(beanName);
            if(bean == null){
                bean = createBean(beanName,beanDefinition);
                singletonObject.put(beanName,bean);
            }
            // get
            return bean;
        }else {
           // 多列的
            return createBean(beanName,beanDefinition);
        }

    }

}
